package com.lynn.common.net

import com.lynn.common.net.entity.BaseResponse
import com.lynn.common.net.exception.HttpErrorHandler
import com.lynn.common.net.exception.ServerException
import com.lynn.common.net.interceptor.RequestInterceptor
import com.lynn.common.net.interceptor.ResponseInterceptor
import com.lynn.common.net.listener.IGetAppInfo
import com.lynn.common.utils.encrypt.AES256
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.ObservableTransformer
import io.reactivex.rxjava3.core.Observer
import io.reactivex.rxjava3.functions.Function
import io.reactivex.rxjava3.schedulers.Schedulers
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit


/**
 * @description:
 * @author: bailing
 * @datetime: 2025/5/27 14:49
 **/
object HttpUtils {

    private var appInfo: IGetAppInfo? = null
    private var okHttpClient: OkHttpClient? = null

    // 存储retrofit实例，保证每次得到的是同一个
    private var retrofitHashMap: HashMap<String, Retrofit>? = null


    /**
     * 1、 App初始化时执行
     */
    fun init(appInfo: IGetAppInfo) {
        this.appInfo = appInfo
    }

    /**
     *  2、请求时先调用该方法，创建Service
     */
    fun <T> createService(baseUrl: String, serviceClass: Class<T>): T {
        return getRetrofit(baseUrl, serviceClass)!!.create<T>(serviceClass)
    }

    /**
     * 3、请求调用第二步：
     *
     * @param observer 这个observer要注意不要使用lifecycle中的Observer
     * @param       泛型
     * @return Observable
     */
    fun applySchedulers(observer: Observer<String>): ObservableTransformer<BaseResponse, String> {

        return ObservableTransformer { upstream: Observable<BaseResponse> ->
            val observable: Observable<String> = upstream
                .subscribeOn(Schedulers.io()) //线程订阅
                .observeOn(AndroidSchedulers.mainThread()) //观察Android主线程

                // 对被观察者发送的每1个事件都通过指定的函数处理，从而变换成另外一种事件, 可用于数据类型转换
                .map(getAppErrorHandler()) //判断有没有500的错误，有则进入getAppErrorHandler
                .onErrorResumeNext(HttpErrorHandler())  // 处理网络异常

            //订阅观察者
            observable.subscribe(observer)
            observable
        }
    }


    /**
     * 处理返回的Response
     * 1、解密data
     * 2、业务异常处理
     */
    private fun getAppErrorHandler(): Function<BaseResponse, String> {
        return object : Function<BaseResponse, String> {

            override fun apply(response: BaseResponse): String {
                Logger.d("HttpUtils：Original response: "+ response.msg)
                when {
                    response.httpCode != null && response.httpCode == 200 -> {
                        // 解密data 并返回
                        val realData =
                            if (response.data.isNullOrEmpty()) "" else AES256.decrypt(response.data)
                        return realData ?: ""
                    }
                    else ->{
                        val exception = ServerException()
                        exception.code = response.httpCode
                        exception.msg = response.msg ?: ""
                        throw exception
                    }

                }

            }

        }

    }

    /**
     * 配置Retrofit
     *
     * @param serviceClass 服务类
     * @return Retrofit
     */
    private fun getRetrofit(baseUrl: String, serviceClass: Class<*>): Retrofit? {
        if (retrofitHashMap == null) {
            retrofitHashMap = HashMap<String, Retrofit>()
        }
        if (retrofitHashMap?.get(baseUrl + serviceClass.getName()) != null) {
            //刚才上面定义的Map中键是String，值是Retrofit，当键不为空时，必然有值，有值则直接返回。
            return retrofitHashMap?.get(baseUrl + serviceClass.getName())
        }

        //初始化Retrofit  Retrofit是对OKHttp的封装，通常是对网络请求做处理，也可以处理返回数据。

        //Retrofit构建器
        val builder = Retrofit.Builder()
            //设置访问地址
            .baseUrl(baseUrl)
            //设置OkHttp客户端，传入上面写好的方法即可获得配置后的OkHttp客户端。
            .client(configOkHttpClient())
            //设置数据解析器 会自动把请求返回的结果（json字符串）通过Gson转化工厂自动转化成与其结构相符的实体Bean
            .addConverterFactory(GsonConverterFactory.create())
            //设置请求回调，使用RxJava 对网络返回进行处理
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())

        //retrofit配置完成
        val retrofit = builder.build()
        //放入Map中
        retrofitHashMap?.put(baseUrl + serviceClass.getName(), retrofit)
        //最后返回即可
        return retrofit
    }

    private fun configOkHttpClient(): OkHttpClient {
        if (okHttpClient == null) {
//            val context =this.appInfo?.getApplicationContext()
//            val cacheFile =
//                FileCacheUtil.getCacheDirI(context)
//            val cacheSize = 100 * 1024 * 1024
            //OkHttp构建器
            val builder = OkHttpClient.Builder()
                //设置缓存大小
                //.cache(Cache(cacheSize, cacheSize))
                //设置网络请求超时时长，这里设置为6s
                .connectTimeout(6, TimeUnit.SECONDS)
                //添加请求拦截器，如果接口有请求头的话，可以放在这个拦截器里面
                .addInterceptor(RequestInterceptor(appInfo!!))
                //添加返回拦截器，可用于查看接口的请求耗时，对于网络优化有帮助
                .addInterceptor(ResponseInterceptor())

            //当程序在debug过程中则打印数据日志，方便调试用。
            if (appInfo != null && appInfo!!.isDebug()) {
                //onGetAppInfoListener 不为空且处于debug状态下则初始化日志拦截器
                val httpLoggingInterceptor = HttpLoggingInterceptor()
                //设置要打印日志的内容等级，BODY为主要内容，还有BASIC、HEADERS、NONE。
                httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
                //将拦截器添加到OkHttp构建器中
                builder.addInterceptor(httpLoggingInterceptor)
            }

            //OkHttp配置完成
            okHttpClient = builder.build()
        }
        return okHttpClient!!
    }


}